home *** CD-ROM | disk | FTP | other *** search
/ ADA Programming Guide / ADA Programming Guide.iso / ada_gnu / adainc / a-ngelfu.adb < prev    next >
Text File  |  1996-01-30  |  21KB  |  909 lines

  1. ------------------------------------------------------------------------------
  2. --                                                                          --
  3. --                         GNAT RUNTIME COMPONENTS                          --
  4. --                                                                          --
  5. --                ADA.NUMERICS.GENERIC_ELEMENTARY_FUNCTIONS                 --
  6. --                                                                          --
  7. --                                 B o d y                                  --
  8. --                                                                          --
  9. --                            $Revision: 1.7 $                              --
  10. --                                                                          --
  11. --           Copyright (c) 1992,1993,1994 NYU, All Rights Reserved          --
  12. --                                                                          --
  13. -- The GNAT library is free software; you can redistribute it and/or modify --
  14. -- it under terms of the GNU Library General Public License as published by --
  15. -- the Free Software  Foundation; either version 2, or (at your option) any --
  16. -- later version.  The GNAT library is distributed in the hope that it will --
  17. -- be useful, but WITHOUT ANY WARRANTY;  without even  the implied warranty --
  18. -- of MERCHANTABILITY  or  FITNESS FOR  A PARTICULAR PURPOSE.  See the  GNU --
  19. -- Library  General  Public  License for  more  details.  You  should  have --
  20. -- received  a copy of the GNU  Library  General Public License  along with --
  21. -- the GNAT library;  see the file  COPYING.LIB.  If not, write to the Free --
  22. -- Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.        --
  23. --                                                                          --
  24. ------------------------------------------------------------------------------
  25.  
  26. --  This body is specifically for using an Ada interface to C math.h to get
  27. --  the computation engine. Many special cases are handled locally to avoid
  28. --  unnecessary calls. This is not a "strict" implementation, but takes full
  29. --  advantage of the C functions, e.g. in providing interface to hardware
  30. --  provided versions of the elementary functions.
  31.  
  32. --  A known weakness is that on the x86, all computation is done in Double,
  33. --  which means that a lot of accuracy is lost for the Long_Long_Float case.
  34.  
  35. --  Uses functions sqrt, exp, log, pow, sin, asin, cos, acos, tan, atan,
  36. --  sinh, cosh, tanh from C library via math.h
  37.  
  38. with Ada.Numerics.Aux;
  39.  
  40. package body Ada.Numerics.Generic_Elementary_Functions is
  41.  
  42.    Log_Two : constant := 0.69314_71805_59945_30941_72321_21458_17656_80755;
  43.  
  44.    Two_Pi     : constant Float_Type'Base := 2.0 * Pi;
  45.    Half_Pi    : constant Float_Type'Base := Pi / 2.0;
  46.    Fourth_Pi  : constant Float_Type'Base := Pi / 4.0;
  47.    Epsilon    : constant Float_Type'Base := Float_Type'Base'Epsilon;
  48.    IEpsilon   : constant Float_Type'Base := 1.0 / Epsilon;
  49.  
  50.    subtype Double is Aux.Double;
  51.  
  52.    DEpsilon    : constant Double := Double (Epsilon);
  53.    DIEpsilon   : constant Double := Double (IEpsilon);
  54.  
  55.    -----------------------
  56.    -- Local Subprograms --
  57.    -----------------------
  58.  
  59.    function Exact_Remainder
  60.      (X    : Float_Type'Base;
  61.       Y    : Float_Type'Base)
  62.       return Float_Type'Base;
  63.    --  Computes exact remainder of X divided by Y
  64.  
  65.    function Half_Log_Epsilon return Float_Type'Base;
  66.    --  Function to provide constant: 0.5 * Log (Epsilon)
  67.  
  68.    function Local_Atan
  69.      (Y    : Float_Type'Base;
  70.       X    : Float_Type'Base := 1.0)
  71.       return Float_Type'Base;
  72.    --  Common code for arc tangent after cyele reduction
  73.  
  74.    function Log_Inverse_Epsilon return Float_Type'Base;
  75.    --  Function to provide constant: Log (1.0 / Epsilon)
  76.  
  77.    function Square_Root_Epsilon return Float_Type'Base;
  78.    --  Function to provide constant: Sqrt (Epsilon)
  79.  
  80.    ----------
  81.    -- "**" --
  82.    ----------
  83.  
  84.    function "**" (Left, Right : Float_Type'Base) return Float_Type'Base is
  85.       Result : Float_Type'Base;
  86.  
  87.    begin
  88.       if Left = 0.0
  89.         and then Right = 0.0
  90.       then
  91.          raise Argument_Error;
  92.  
  93.       elsif Left < 0.0 then
  94.          raise Argument_Error;
  95.  
  96.       elsif Right = 0.0 then
  97.          return 1.0;
  98.  
  99.       elsif Left = 0.0 then
  100.          if Right < 0.0 then
  101.             raise Constraint_Error;
  102.          else
  103.             return 0.0;
  104.          end if;
  105.  
  106.       elsif Left = 1.0 then
  107.          return 1.0;
  108.  
  109.       elsif Right = 1.0 then
  110.          return Left;
  111.  
  112.       elsif Right = 2.0 then
  113.          return Left * Left;
  114.       end if;
  115.  
  116.       return Float_Type'Base (Aux.pow (Double (Left), Double (Right)));
  117.  
  118.    exception
  119.       when others =>
  120.          raise Constraint_Error;
  121.    end "**";
  122.  
  123.    ------------
  124.    -- Arccos --
  125.    ------------
  126.  
  127.    --  Natural cycle
  128.  
  129.    function Arccos (X : Float_Type'Base) return Float_Type'Base is
  130.       Temp : Float_Type'Base;
  131.  
  132.    begin
  133.       if abs X > 1.0 then
  134.          raise Argument_Error;
  135.  
  136.       elsif abs X < Square_Root_Epsilon then
  137.          return Pi / 2.0;
  138.  
  139.       elsif X = 1.0 then
  140.          return 0.0;
  141.  
  142.       elsif X = -1.0 then
  143.          return Pi;
  144.       end if;
  145.  
  146.       Temp := Float_Type'Base (Aux.acos (Double (X)));
  147.  
  148.       if Temp < 0.0 then
  149.          Temp := Pi + Temp;
  150.       end if;
  151.  
  152.       return Temp;
  153.    end Arccos;
  154.  
  155.    --  Arbitrary cycle
  156.  
  157.    function Arccos (X, Cycle : Float_Type'Base) return Float_Type'Base is
  158.       Temp : Float_Type'Base;
  159.  
  160.    begin
  161.       if Cycle <= 0.0 then
  162.          raise Argument_Error;
  163.  
  164.       elsif abs X > 1.0 then
  165.          raise Argument_Error;
  166.  
  167.       elsif abs X < Square_Root_Epsilon then
  168.          return Cycle / 4.0;
  169.  
  170.       elsif X = 1.0 then
  171.          return 0.0;
  172.  
  173.       elsif X = -1.0 then
  174.          return Cycle / 2.0;
  175.       end if;
  176.  
  177.       Temp := Arctan (Sqrt (1.0 - X * X) / X, 1.0, Cycle);
  178.  
  179.       if Temp < 0.0 then
  180.          Temp := Cycle / 2.0 + Temp;
  181.       end if;
  182.  
  183.       return Temp;
  184.    end Arccos;
  185.  
  186.    -------------
  187.    -- Arccosh --
  188.    -------------
  189.  
  190.    function Arccosh (X : Float_Type'Base) return Float_Type'Base is
  191.    begin
  192.       --  Return Log (X - Sqrt (X * X - 1.0));  double valued,
  193.       --    only positive value returned
  194.       --  What is this comment ???
  195.  
  196.       if X < 1.0 then
  197.          raise Argument_Error;
  198.  
  199.       elsif X < 1.0 + Square_Root_Epsilon then
  200.          return X - 1.0;
  201.  
  202.       elsif abs X > 1.0 / Square_Root_Epsilon then
  203.          return Log (X) + Log_Two;
  204.  
  205.       else
  206.          return Log (X + Sqrt (X * X - 1.0));
  207.       end if;
  208.    end Arccosh;
  209.  
  210.    ------------
  211.    -- Arccot --
  212.    ------------
  213.  
  214.    --  Natural cycle
  215.  
  216.    function Arccot
  217.      (X    : Float_Type'Base;
  218.       Y    : Float_Type'Base := 1.0)
  219.       return Float_Type'Base
  220.    is
  221.    begin
  222.       --  Just reverse arguments
  223.  
  224.       return Arctan (Y, X);
  225.    end Arccot;
  226.  
  227.    --  Arbitrary cycle
  228.  
  229.    function Arccot
  230.      (X     : Float_Type'Base;
  231.       Y     : Float_Type'Base := 1.0;
  232.       Cycle : Float_Type'Base)
  233.       return  Float_Type'Base
  234.    is
  235.    begin
  236.       --  Just reverse arguments
  237.  
  238.       return Arctan (Y, X, Cycle);
  239.    end Arccot;
  240.  
  241.    -------------
  242.    -- Arccoth --
  243.    -------------
  244.  
  245.    function Arccoth (X : Float_Type'Base) return Float_Type'Base is
  246.    begin
  247.       if abs X = 1.0 then
  248.          raise Constraint_Error;
  249.  
  250.       elsif abs X < 1.0 then
  251.          raise Argument_Error;
  252.  
  253.       elsif abs X > 1.0 / Epsilon then
  254.          return 0.0;
  255.  
  256.       else
  257.          return 0.5 * Log ((1.0 + X) / (X - 1.0));
  258.       end if;
  259.    end Arccoth;
  260.  
  261.    ------------
  262.    -- Arcsin --
  263.    ------------
  264.  
  265.    --  Natural cycle
  266.  
  267.    function Arcsin (X : Float_Type'Base) return Float_Type'Base is
  268.    begin
  269.       if abs X > 1.0 then
  270.          raise Argument_Error;
  271.  
  272.       elsif abs X < Square_Root_Epsilon then
  273.          return X;
  274.  
  275.       elsif X = 1.0 then
  276.          return Pi / 2.0;
  277.  
  278.       elsif X = -1.0 then
  279.          return -Pi / 2.0;
  280.       end if;
  281.  
  282.       return Float_Type'Base (Aux.asin (Double (X)));
  283.    end Arcsin;
  284.  
  285.    --  Arbitrary cycle
  286.  
  287.    function Arcsin (X, Cycle : Float_Type'Base) return Float_Type'Base is
  288.    begin
  289.       if Cycle <= 0.0 then
  290.          raise Argument_Error;
  291.  
  292.       elsif abs X > 1.0 then
  293.          raise Argument_Error;
  294.  
  295.       elsif X = 0.0 then
  296.          return X;
  297.  
  298.       elsif X = 1.0 then
  299.          return Cycle / 4.0;
  300.  
  301.       elsif X = -1.0 then
  302.          return -Cycle / 4.0;
  303.       end if;
  304.  
  305.       return Arctan (X / Sqrt (1.0 - X * X), 1.0, Cycle);
  306.    end Arcsin;
  307.  
  308.    -------------
  309.    -- Arcsinh --
  310.    -------------
  311.  
  312.    function Arcsinh (X : Float_Type'Base) return Float_Type'Base is
  313.    begin
  314.       if abs X < Square_Root_Epsilon then
  315.          return X;
  316.  
  317.       elsif X > 1.0 / Square_Root_Epsilon then
  318.          return Log (X) + Log_Two;
  319.  
  320.       elsif X < -1.0 / Square_Root_Epsilon then
  321.          return -(Log (-X) + Log_Two);
  322.  
  323.       elsif X < 0.0 then
  324.          return -Log (abs X + Sqrt (X * X + 1.0));
  325.  
  326.       else
  327.          return Log (X + Sqrt (X * X + 1.0));
  328.       end if;
  329.    end Arcsinh;
  330.  
  331.    ------------
  332.    -- Arctan --
  333.    ------------
  334.  
  335.    --  Natural cycle
  336.  
  337.    function Arctan
  338.      (Y    : Float_Type'Base;
  339.       X    : Float_Type'Base := 1.0)
  340.       return Float_Type'Base
  341.    is
  342.       T : Float_Type'Base;
  343.  
  344.    begin
  345.       if X = 0.0
  346.         and then Y = 0.0
  347.       then
  348.          raise Argument_Error;
  349.  
  350.       elsif Y = 0.0 then
  351.          if X > 0.0 then
  352.             return 0.0;
  353.          else -- X < 0.0
  354.             return Pi;
  355.          end if;
  356.  
  357.       elsif X = 0.0 then
  358.          if Y > 0.0 then
  359.             return Half_Pi;
  360.          else -- Y < 0.0
  361.             return -Half_Pi;
  362.          end if;
  363.  
  364.       else
  365.          return Local_Atan (Y, X);
  366.       end if;
  367.    end Arctan;
  368.  
  369.    --  Arbitrary cycle
  370.  
  371.    function Arctan
  372.      (Y     : Float_Type'Base;
  373.       X     : Float_Type'Base := 1.0;
  374.       Cycle : Float_Type'Base)
  375.       return  Float_Type'Base
  376.    is
  377.    begin
  378.       if Cycle <= 0.0 then
  379.          raise Argument_Error;
  380.  
  381.       elsif X = 0.0
  382.         and then Y = 0.0
  383.       then
  384.          raise Argument_Error;
  385.  
  386.       elsif Y = 0.0 then
  387.          if X > 0.0 then
  388.             return 0.0;
  389.          else -- X < 0.0
  390.             return Cycle / 2.0;
  391.          end if;
  392.  
  393.       elsif X = 0.0 then
  394.          if Y > 0.0 then
  395.             return Cycle / 4.0;
  396.          else -- Y < 0.0
  397.             return -Cycle / 4.0;
  398.          end if;
  399.  
  400.       else
  401.          return Local_Atan (Y, X) *  Cycle / Two_Pi;
  402.       end if;
  403.    end Arctan;
  404.  
  405.    -------------
  406.    -- Arctanh --
  407.    -------------
  408.  
  409.    function Arctanh (X : Float_Type'Base) return Float_Type'Base is
  410.    begin
  411.       if abs X = 1.0 then
  412.          raise Constraint_Error;
  413.  
  414.       elsif abs X > 1.0 then
  415.          raise Argument_Error;
  416.  
  417.       elsif abs X < Square_Root_Epsilon then
  418.          return X;
  419.  
  420.       else
  421.          return 0.5 * Log ((1.0 + X) / (1.0 - X));
  422.       end if;
  423.    end Arctanh;
  424.  
  425.    ---------
  426.    -- Cos --
  427.    ---------
  428.  
  429.    --  Natural cycle
  430.  
  431.    function Cos (X : Float_Type'Base) return Float_Type'Base is
  432.    begin
  433.       if X = 0.0 then
  434.          return 1.0;
  435.  
  436.       elsif abs X < Square_Root_Epsilon then
  437.          return 1.0;
  438.  
  439.       end if;
  440.  
  441.       return Float_Type'Base (Aux.Cos (Double (X)));
  442.    end Cos;
  443.  
  444.    --  Arbitrary cycle
  445.  
  446.    function Cos (X, Cycle : Float_Type'Base) return Float_Type'Base is
  447.       T : Float_Type'Base;
  448.  
  449.    begin
  450.       if Cycle <= 0.0 then
  451.          raise Argument_Error;
  452.  
  453.       elsif X = 0.0 then
  454.          return 1.0;
  455.       end if;
  456.  
  457.       T := Exact_Remainder (abs (X), Cycle) / Cycle;
  458.  
  459.       if T = 0.25
  460.         or else T = 0.75
  461.         or else T = -0.25
  462.         or else T = -0.75
  463.       then
  464.          return 0.0;
  465.  
  466.       elsif T = 0.5 or T = -0.5 then
  467.          return -1.0;
  468.       end if;
  469.  
  470.       return Float_Type'Base (Aux.Cos (Double (T * Two_Pi)));
  471.    end Cos;
  472.  
  473.    ----------
  474.    -- Cosh --
  475.    ----------
  476.  
  477.    function Cosh (X : Float_Type'Base) return Float_Type'Base is
  478.       Exp_X : Float_Type'Base;
  479.  
  480.    begin
  481.       if abs X < Square_Root_Epsilon then
  482.          return 1.0;
  483.  
  484.       elsif abs X > Log_Inverse_Epsilon then
  485.          return Exp ((abs X) - Log_Two);
  486.       end if;
  487.  
  488.       return Float_Type'Base (Aux.cosh (Double (X)));
  489.  
  490.    exception
  491.       when others =>
  492.          raise Constraint_Error;
  493.    end Cosh;
  494.  
  495.    ---------
  496.    -- Cot --
  497.    ---------
  498.  
  499.    --  Natural cycle
  500.  
  501.    function Cot (X : Float_Type'Base) return Float_Type'Base is
  502.    begin
  503.       if abs X < Square_Root_Epsilon then
  504.          return 1.0 / X;
  505.       end if;
  506.  
  507.       return 1.0 / Float_Type'Base (Aux.tan (Double (X)));
  508.    end Cot;
  509.  
  510.    --  Arbitrary cycle
  511.  
  512.    function Cot (X, Cycle : Float_Type'Base) return Float_Type'Base is
  513.    begin
  514.       if Cycle <= 0.0 then
  515.          raise Argument_Error;
  516.  
  517.       elsif abs X < Square_Root_Epsilon then
  518.          return 1.0 / X;
  519.       end if;
  520.  
  521.       return  Cos (X, Cycle) / Sin (X, Cycle);
  522.    end Cot;
  523.  
  524.    ----------
  525.    -- Coth --
  526.    ----------
  527.  
  528.    function Coth (X : Float_Type'Base) return Float_Type'Base is
  529.    begin
  530.       if X < Half_Log_Epsilon then
  531.          return -1.0;
  532.  
  533.       elsif X > -Half_Log_Epsilon then
  534.          return 1.0;
  535.  
  536.       elsif abs X < Square_Root_Epsilon then
  537.          return 1.0 / X;
  538.       end if;
  539.  
  540.       return 1.0 / Float_Type'Base (Aux.tanh (Double (X)));
  541.    end Coth;
  542.  
  543.    ---------------------
  544.    -- Exact_Remainder --
  545.    ---------------------
  546.  
  547.    function Exact_Remainder
  548.      (X    : Float_Type'Base;
  549.       Y    : Float_Type'Base)
  550.       return Float_Type'Base
  551.    is
  552.       Denominator : Float_Type'Base := abs X;
  553.       Divisor     : Float_Type'Base := abs Y;
  554.       Reducer     : Float_Type'Base;
  555.       Sign        : Float_Type'Base := 1.0;
  556.  
  557.    begin
  558.       if Y = 0.0 then
  559.          raise Constraint_Error;
  560.  
  561.       elsif X = 0.0 then
  562.          return 0.0;
  563.  
  564.       elsif X = Y then
  565.          return 0.0;
  566.  
  567.       elsif Denominator < Divisor then
  568.          return X;
  569.       end if;
  570.  
  571.       while Denominator >= Divisor loop
  572.  
  573.          --  Put divisors mantissa with denominators exponent to make reducer
  574.  
  575.          Reducer := Divisor;
  576.  
  577.          begin
  578.             while Reducer * 1_048_576.0 < Denominator loop
  579.                Reducer := Reducer * 1_048_576.0;
  580.             end loop;
  581.  
  582.          exception
  583.             when others => null;
  584.          end;
  585.  
  586.          begin
  587.             while Reducer * 1_024.0 < Denominator loop
  588.                Reducer := Reducer * 1_024.0;
  589.             end loop;
  590.  
  591.          exception
  592.             when others => null;
  593.          end;
  594.  
  595.          begin
  596.             while Reducer * 2.0 < Denominator loop
  597.                Reducer := Reducer * 2.0;
  598.             end loop;
  599.  
  600.          exception
  601.             when others => null;
  602.          end;
  603.  
  604.          Denominator := Denominator - Reducer;
  605.       end loop;
  606.  
  607.       if X < 0.0 then
  608.          return -Denominator;
  609.       else
  610.          return Denominator;
  611.       end if;
  612.    end Exact_Remainder;
  613.  
  614.    ---------
  615.    -- Exp --
  616.    ---------
  617.  
  618.    function Exp (X : Float_Type'Base) return Float_Type'Base is
  619.       Result : Float_Type'Base;
  620.  
  621.    begin
  622.       if X = 0.0 then
  623.          return 1.0;
  624.  
  625.       else
  626.          Result := Float_Type'Base (Aux.Exp (Double (X)));
  627.  
  628.          --  The check here catches the case of Exp returning IEEE infinity
  629.  
  630.          if Result > Float_Type'Base'Last then
  631.             raise Constraint_Error;
  632.          else
  633.             return Result;
  634.          end if;
  635.       end if;
  636.    end Exp;
  637.  
  638.    ----------------------
  639.    -- Half_Log_Epsilon --
  640.    ----------------------
  641.  
  642.    --  Cannot precompute this constant, because this is required to be a
  643.    --  pure package, which allows no state. A pity, but no way around it!
  644.  
  645.    function Half_Log_Epsilon return Float_Type'Base is
  646.    begin
  647.       return 0.5 * Float_Type'Base (Aux.Log (DEpsilon));
  648.    end Half_Log_Epsilon;
  649.  
  650.    ----------------
  651.    -- Local_Atan --
  652.    ----------------
  653.  
  654.    function Local_Atan
  655.      (Y    : Float_Type'Base;
  656.       X    : Float_Type'Base := 1.0)
  657.       return Float_Type'Base
  658.    is
  659.       Z        : Float_Type'Base;
  660.       Raw_Atan : Float_Type'Base;
  661.  
  662.    begin
  663.       if abs Y > abs X then
  664.          Z := abs (X / Y);
  665.       else
  666.          Z := abs (Y / X);
  667.       end if;
  668.  
  669.       if Z < Square_Root_Epsilon then
  670.          Raw_Atan := Z;
  671.  
  672.       elsif Z = 1.0 then
  673.          Raw_Atan := Pi / 4.0;
  674.  
  675.       elsif Z < Square_Root_Epsilon then
  676.          Raw_Atan := Z;
  677.  
  678.       else
  679.          Raw_Atan := Float_Type'Base (Aux.Atan (Double (Z)));
  680.       end if;
  681.  
  682.       if abs Y > abs X then
  683.          Raw_Atan := Half_Pi - Raw_Atan;
  684.       end if;
  685.  
  686.       if X > 0.0 then
  687.          if Y > 0.0 then
  688.             return Raw_Atan;
  689.          else                 --  Y < 0.0
  690.             return -Raw_Atan;
  691.          end if;
  692.  
  693.       else                    --  X < 0.0
  694.          if Y > 0.0 then
  695.             return Pi - Raw_Atan;
  696.          else                  --  Y < 0.0
  697.             return -(Pi - Raw_Atan);
  698.          end if;
  699.       end if;
  700.    end Local_Atan;
  701.  
  702.    ---------
  703.    -- Log --
  704.    ---------
  705.  
  706.    --  Natural base
  707.  
  708.    function Log (X : Float_Type'Base) return Float_Type'Base is
  709.    begin
  710.       if X < 0.0 then
  711.          raise Argument_Error;
  712.  
  713.       elsif X = 0.0 then
  714.          raise Constraint_Error;
  715.  
  716.       elsif X = 1.0 then
  717.          return 0.0;
  718.       end if;
  719.  
  720.       return Float_Type'Base (Aux.Log (Double (X)));
  721.    end Log;
  722.  
  723.    --  Arbitrary base
  724.  
  725.    function Log (X, Base : Float_Type'Base) return Float_Type'Base is
  726.    begin
  727.       if X < 0.0 then
  728.          raise Argument_Error;
  729.  
  730.       elsif Base <= 0.0 or else Base = 1.0 then
  731.          raise Argument_Error;
  732.  
  733.       elsif X = 0.0 then
  734.          raise Constraint_Error;
  735.  
  736.       elsif X = 1.0 then
  737.          return 0.0;
  738.       end if;
  739.  
  740.       return Float_Type'Base (Aux.Log (Double (X)) / Aux.Log (Double (Base)));
  741.    end Log;
  742.  
  743.    -------------------------
  744.    -- Log_Inverse_Epsilon --
  745.    -------------------------
  746.  
  747.    --  Cannot precompute this constant, because this is required to be a
  748.    --  pure package, which allows no state. A pity, but no way around it!
  749.  
  750.    function Log_Inverse_Epsilon return Float_Type'Base is
  751.    begin
  752.       return Float_Type'Base (Aux.Log (DIEpsilon));
  753.    end Log_Inverse_Epsilon;
  754.  
  755.    ---------
  756.    -- Sin --
  757.    ---------
  758.  
  759.    --  Natural cycle
  760.  
  761.    function Sin (X : Float_Type'Base) return Float_Type'Base is
  762.    begin
  763.       if abs X < Square_Root_Epsilon then
  764.          return X;
  765.       end if;
  766.  
  767.       return Float_Type'Base (Aux.Sin (Double (X)));
  768.    end Sin;
  769.  
  770.    --  Arbitrary cycle
  771.  
  772.    function Sin (X, Cycle : Float_Type'Base) return Float_Type'Base is
  773.       T : Float_Type'Base;
  774.  
  775.    begin
  776.       if Cycle <= 0.0 then
  777.          raise Argument_Error;
  778.  
  779.       elsif X = 0.0 then
  780.          return X;
  781.       end if;
  782.  
  783.       T := Exact_Remainder (X, Cycle) / Cycle;
  784.  
  785.       if T = 0.0 or T = 0.5 or T = -0.5 then
  786.          return 0.0;
  787.  
  788.       elsif T = 0.25 or T = -0.75 then
  789.          return 1.0;
  790.  
  791.       elsif T = -0.25 or T = 0.75 then
  792.          return -1.0;
  793.  
  794.       end if;
  795.  
  796.       return  Float_Type'Base (Aux.Sin (Double (T * Two_Pi)));
  797.    end Sin;
  798.  
  799.    ----------
  800.    -- Sinh --
  801.    ----------
  802.  
  803.    function Sinh (X : Float_Type'Base) return Float_Type'Base is
  804.       Exp_X : Float_Type'Base;
  805.  
  806.    begin
  807.       if abs X < Square_Root_Epsilon then
  808.          return X;
  809.  
  810.       elsif  X > Log_Inverse_Epsilon then
  811.          return Exp (X - Log_Two);
  812.  
  813.       elsif X < -Log_Inverse_Epsilon then
  814.          return -Exp ((-X) - Log_Two);
  815.       end if;
  816.  
  817.       return Float_Type'Base (Aux.Sinh (Double (X)));
  818.  
  819.    exception
  820.       when others =>
  821.          raise Constraint_Error;
  822.    end Sinh;
  823.  
  824.    -------------------------
  825.    -- Square_Root_Epsilon --
  826.    -------------------------
  827.  
  828.    --  Cannot precompute this constant, because this is required to be a
  829.    --  pure package, which allows no state. A pity, but no way around it!
  830.  
  831.    function Square_Root_Epsilon return Float_Type'Base is
  832.    begin
  833.       return Float_Type'Base (Aux.Sqrt (DEpsilon));
  834.    end Square_Root_Epsilon;
  835.  
  836.    ----------
  837.    -- Sqrt --
  838.    ----------
  839.  
  840.    function Sqrt (X : Float_Type'Base) return Float_Type'Base is
  841.    begin
  842.       if X < 0.0 then
  843.          raise Argument_Error;
  844.  
  845.       --  Special case Sqrt (0.0) to preserve possible minus sign per IEEE
  846.  
  847.       elsif X = 0.0 then
  848.          return X;
  849.  
  850.       --  Sqrt (1.0) must be exact for good complex accuracy
  851.  
  852.       elsif X = 1.0 then
  853.          return 1.0;
  854.  
  855.       end if;
  856.  
  857.       return Float_Type'Base (Aux.Sqrt (Double (X)));
  858.    end Sqrt;
  859.  
  860.    ---------
  861.    -- Tan --
  862.    ---------
  863.  
  864.    --  Natural cycle
  865.  
  866.    function Tan (X : Float_Type'Base) return Float_Type'Base is
  867.    begin
  868.       if abs X < Square_Root_Epsilon then
  869.          return X;
  870.       end if;
  871.  
  872.       return Float_Type'Base (Aux.tan (Double (X)));
  873.    end Tan;
  874.  
  875.    --  Arbitrary cycle
  876.  
  877.    function Tan (X, Cycle : Float_Type'Base) return Float_Type'Base is
  878.    begin
  879.       if Cycle <= 0.0 then
  880.          raise Argument_Error;
  881.  
  882.       elsif X = 0.0 then
  883.          return X;
  884.       end if;
  885.  
  886.       return Sin (X, Cycle) / Cos (X, Cycle);
  887.    end Tan;
  888.  
  889.    ----------
  890.    -- Tanh --
  891.    ----------
  892.  
  893.    function Tanh (X : Float_Type'Base) return Float_Type'Base is
  894.    begin
  895.       if X < Half_Log_Epsilon then
  896.          return -1.0;
  897.  
  898.       elsif X > -Half_Log_Epsilon then
  899.          return 1.0;
  900.  
  901.       elsif abs X < Square_Root_Epsilon then
  902.          return X;
  903.       end if;
  904.  
  905.       return Float_Type'Base (Aux.tanh (Double (X)));
  906.    end Tanh;
  907.  
  908. end Ada.Numerics.Generic_Elementary_Functions;
  909.